package com.kai.steering.data.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.kai.steering.common.web.vo.ReturnCodeExt;
import com.kai.steering.data.service.databus.enums.CanUsedExceptionEnum;
import com.kai.steering.data.service.entity.domainObject.KnowledgeDO;
import com.kai.steering.data.service.entity.domainObject.QuestionDO;
import com.kai.steering.data.service.entity.domainObject.TestDO;
import com.kai.steering.data.service.entity.domainObject.WarehouseDO;
import com.kai.steering.data.service.entity.dto.TestQueryDTO;
import com.kai.steering.data.service.entity.po.Question;
import com.kai.steering.data.service.entity.po.Test;
import com.kai.steering.data.service.entity.po.TestQuestion;
import com.kai.steering.data.service.entity.po.WarehouseTest;
import com.kai.steering.data.service.entity.vo.TestVO;
import com.kai.steering.data.service.mapper.TestMapper;
import com.kai.steering.data.service.mapper.TestQuestiontMapper;
import com.kai.steering.data.service.service.*;
import com.kai.steering.common.web.service.impl.BaseServiceImpl;
import com.kai.steering.common.vo.Page;

import com.kai.steering.data.service.util.ConfigurationReading.QuestionExcelAllocation;
import com.kai.steering.data.service.util.ConfigurationReading.TestExcelAllocation;
import com.kai.steering.data.service.util.EqualsUtil;
import com.kai.steering.data.service.util.ListUtil;
import com.kai.steering.data.service.util.OfficeUtil;
import com.kai.steering.exception.CanUsedException;
import com.kai.steering.exception.ExcelException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;

import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import org.springframework.web.multipart.MultipartFile;

/**
 * <pre>
 * 试卷 服务实现类
 * </pre>
 *
 * @author kai
 * @since 2022-02-23
 */
@Slf4j
@Service
public class TestServiceImpl extends BaseServiceImpl<TestMapper, Test> implements TestService {

    @Autowired
    private TestMapper testMapper;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private KnowledgeService knowledgeService;
    @Autowired
    private QuestionService questionService;
    @Autowired
    TestQuestiontMapper testQuestiontMapper;
    @Autowired
    TestQuestionService testQuestiontService;
    @Autowired
    TestExcelAllocation testExcelAllocation;
    @Autowired
    QuestionExcelAllocation questionExcelAllocation;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public TestDO saveTest(TestDO testDO) {
        /**
         * 参数校验
         */
        TestDO old = getTestByName(testDO.getTestName());
        //name
        if (old != null && StringUtils.isNotEmpty(old.getTestId())) {
            throw ReturnCodeExt.PARAMETER_CHECK.getException("对象[" + testDO.getTestName() + "]存在");
        }
        //warehouseId

        //knowledges
        //校验知识点存在
        boolean allExists = knowledgeService.isAllExists(testDO.getKnowledgeDOs());
        if (!allExists) {
            throw ReturnCodeExt.PARAMETER_CHECK.getException("知识点错误");
        }

        testDO.setUsable(null);
        testDO.setQuestions(null);

        Test test = new Test(testDO);
        test.setCreationDatetime(new Date());
        test.setDeleteDatetime(null);
        TestDO newTestDO = null;
        if (super.save(test)){
            newTestDO=new TestDO(test);
        }
        return newTestDO;
    }

    @Override
    public TestDO getTestByName(String testName) {
        Test test = testMapper.getTestByName(testName);
        TestDO testDO = new TestDO(test);
        return testDO;
    }

    @Override
    public boolean exportTest(List<String> testIds) {
        return false;
    }

    @Override
    public String importTest(MultipartFile file) {
        List<List> surface = null;
        try {
            surface = OfficeUtil.excelReaderPage(file.getInputStream(), 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
        TestDO testDO = new TestDO();

//        Object result=null;
//        result = ListUtil.lineAcquisition(surface,testExcelAllocation.getQuestionColumn());


        List<List> questionData = surface.subList(testExcelAllocation.getDataLine(), surface.size());
        //清除空白行
        Iterator<List> iterator = questionData.iterator();
        while (iterator.hasNext()) {
            List item = iterator.next();
            Object o = item.get(testExcelAllocation.getQuestionColumn());
            if (o==null||o.equals("")) {
                iterator.remove();
            }
        }

        ArrayList<QuestionDO> questionDOs = questionService.tableConversionQuestionDO(questionData);
        List<ExcelException> incorrectDataS = questionService.saveQuestionAll(questionDOs);

        List testNameLine = surface.get(testExcelAllocation.getTestNameLine());
        testDO.setTestName(testNameLine.get(testExcelAllocation.getTestNameColumn()).toString());
        List testDetailsLine = surface.get(testExcelAllocation.getTestDetailsLine());

        testDO.setTestInformation(testDetailsLine.get(testExcelAllocation.getTestDetailsColumn()).toString());
        TestDO newTestDO = saveTest(testDO);
        boolean b = exportQuestionDo(newTestDO.getTestId(), questionDOs);
        if (incorrectDataS.size()>0){
            throw new CanUsedException(CanUsedExceptionEnum.TEST_EXCEPTION,incorrectDataS);
        }
        return newTestDO.getTestId();
    }

    public boolean exportQuestion(String testID, List<String> questionsIDs) {
        TestDO testById = getTestById(testID, null);
        if (testById==null||StringUtils.isEmpty(testById.getTestId())){
            throw ReturnCodeExt.PARAMETER_CHECK.getException("对象[" + testID+ "]不存在");
        }
        List<QuestionDO> question = questionService.getQuestionByIds(questionsIDs,null);
        if (question==null||question.size()!=questionsIDs.size()){
            throw ReturnCodeExt.PARAMETER_CHECK.getException("对象[ 题目中部分id" + "]不存在");
        }
        List<TestQuestion> testQuestions = TestQuestion.generateTestQuestions(testID, questionsIDs);
        boolean b = testQuestiontService.saveBatch(testQuestions);
        return b;
    }
    private boolean exportQuestionDo(String testID, List<QuestionDO> questionDOs) {
        List<String> collect = questionDOs.stream().map(questionDO -> {
            return questionDO.getQuestionId();
        }).collect(Collectors.toList());
        List<TestQuestion> testQuestions = TestQuestion.generateTestQuestions(testID, collect);
        boolean b = testQuestiontService.saveBatch(testQuestions);
        return b;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateTest(Serializable id, TestDO testDO) {
        /**
         * 参数验证
         */
//        //id
        Test test = new Test(testDO);
        HashMap<String, Boolean> parameterMap = new HashMap<>();
        parameterMap.put("knowledgeExist",true);

        TestDO oldTestDO = getTestById(id, parameterMap);
        if (oldTestDO == null || StringUtils.isEmpty(oldTestDO.getTestId())) {
            throw ReturnCodeExt.PARAMETER_CHECK.getException("对象[" + testDO.getTestName() + "]不存在");
        }
        //knowledges
        //校验知识点存在
        boolean allExists = knowledgeService.isAllExists(testDO.getKnowledgeDOs());
        if (!allExists) {
            throw ReturnCodeExt.PARAMETER_CHECK.getException("知识点错误");
        }
        //
        //校验知识是否变动
        boolean b = knowledgeService.checkKnowledgeChange(testDO.getKnowledgeDOs(), oldTestDO.getKnowledgeDOs());
        if (b) {
            test.setKnowledgeId(null);
        }


        return super.updateById(test);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteTest(Serializable id) {
        TestDO oldTestDO = getTestById(id, null);
        if (oldTestDO == null || StringUtils.isEmpty(oldTestDO.getTestId())) {
            throw ReturnCodeExt.PARAMETER_CHECK.getException("对象[" + id + "]不存在");
        }
        boolean b = super.removeById(id);
        return b;
    }

    @Override
    public TestDO getTestById(Serializable id, HashMap<String,Boolean>parameterMap) {
        Test testById = testMapper.selectById(id);
        TestDO testDO = new TestDO(testById);
        if (parameterMap!=null){
            if (EqualsUtil.objectBooleanEquals(parameterMap.get("knowledgeExist")) && testById.getKnowledgeId() != null) {
                List<String> knowledgeIds = Arrays.asList(StringUtils.splitByWholeSeparator(testById.getKnowledgeId(), ","));
                List<KnowledgeDO> knowledgeByIds = knowledgeService.getKnowledgeByIds(knowledgeIds);
                testDO.setKnowledgeDOs(knowledgeByIds);
            }
            if (EqualsUtil.objectBooleanEquals(parameterMap.get("questionExist")) ) {
                List<QuestionDO> testquestion = questionService.getTestquestion(id, parameterMap);
                testDO.setQuestions(testquestion);
            }
        }




        return testDO;
    }

    @Override
    public List<TestDO> getAllTest() {
        List<Test> testlist = this.list();
        List<TestDO> result = testlist.stream()
                .map(test -> {
                    TestDO testVo = new TestDO();
                    BeanUtil.copyProperties(test, testVo);
                    return testVo;
                })
                .collect(Collectors.toList());
        return result;
    }

    @Override
    public Page<TestDO> getTestPageList(TestQueryDTO testQueryDTO) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page page = setPageParam(
                testQueryDTO, OrderItem.desc("create_time")
        );

        QueryWrapper<Test> queryWrapper = new QueryWrapper<>();
        //test_id
        if (StringUtils.isNotEmpty(testQueryDTO.getTestId())) {
            queryWrapper.eq("test_id", testQueryDTO.getTestId());
        }
        //test_name
        if (StringUtils.isNotEmpty(testQueryDTO.getTestName())) {
            queryWrapper.eq("test_name", testQueryDTO.getTestName());
        }
        //founder
        if (StringUtils.isNotEmpty(testQueryDTO.getFounder())) {
            queryWrapper.eq("founder", testQueryDTO.getFounder());
        }
        //test_information
        if (StringUtils.isNotEmpty(testQueryDTO.getTestInformation())) {
            queryWrapper.eq("test_information", testQueryDTO.getTestInformation());
        }
        //creation_datetime
        //开始时间 创建
        if (testQueryDTO.getCreationDateTerminus() == null) {
            queryWrapper.ge("creation_datetime", testQueryDTO.getCreationDateOrigin());
        }
        //结束时间 创建
        if (testQueryDTO.getCreationDateTerminus() == null) {
            queryWrapper.le("creation_datetime", testQueryDTO.getCreationDateTerminus());
        }


//        //warehouse_id
//        if (StringUtils.isNotEmpty(testQueryDTO.getCreationDateTerminus())) {
//            queryWrapper.eq("warehouse_id", testQueryDTO.getWarehouseId());
//        }
        //knowledge_id
//        if (StringUtils.isNotEmpty(testQueryDTO.getKnowledges())) {
//            queryWrapper.eq("knowledge_id", testQueryDTO.getWarehouseId());
//        }
//
//        //usable
//            queryWrapper.eq("usable", 0);
//        //delete_datetime
//        if (StringUtils.isNotEmpty(testQueryDTO.getWarehouseId())) {
//            queryWrapper.eq("delete_datetime", testQueryDTO.getCreationDateOrigin());
//        }


        //组合条件
        IPage<Test> entityPage = testMapper.selectPage(page, queryWrapper);
        List<TestDO> result = entityPage.getRecords().stream()
                .map(test -> {
                    TestDO testDO = new TestDO();
                    BeanUtil.copyProperties(test, testDO);
                    return testDO;
                })
                .collect(Collectors.toList());

        return Page.<TestDO>builder()
                .currPage(testQueryDTO.getPageNo())
                .pageSize(testQueryDTO.getPageSize())
                .totalCount((int) entityPage.getTotal())
                .list(result)
                .build();
    }


    @Override
    public boolean isExists(String key, String val, Serializable id) {
        QueryWrapper<Test> qw = new QueryWrapper<>();
        qw.eq(key, val);
        if (id != null) {
            qw.ne("id", id);
        }
        int num = this.count(qw);
        return num > 0;
    }

    /**
     * 生成完整的test
     *
     * @param testDO
     * @return
     */
    private TestDO testAll(TestDO testDO) {
        testDO = test_AllKnowledge(testDO);
        testDO = test_AllQuestion(testDO);
        return testDO;
    }

    /**
     * 生成完整知识点的test
     *
     * @param testDO
     * @return
     */
    private TestDO test_AllKnowledge(TestDO testDO) {
        if (testDO.getKnowledgeDOs() == null) {
            return testDO;
        }
        List<KnowledgeDO> knowledges = testDO.getKnowledgeDOs();
        List<String> collect = knowledges.stream().map(knowledgeDO -> {
            return knowledgeDO.getKnowledgeId();
        }).collect(Collectors.toList());
        knowledges = knowledgeService.getKnowledgeByIds(collect);
        testDO.setKnowledgeDOs(knowledges);
        return testDO;
    }

    /**
     * 生成完整题目的test
     *
     * @param testDO
     * @return
     */
    private TestDO test_AllQuestion(TestDO testDO) {
        if (testDO.getKnowledgeDOs() == null) {
            return testDO;
        }
        List<QuestionDO> questions = testDO.getQuestions();
        List<String> collect = questions.stream().map(knowledgeDO -> {
            return knowledgeDO.getQuestionId();
        }).collect(Collectors.toList());
        questions = questionService.getQuestionByIds(collect,null);
        testDO.setQuestions(questions);
        return testDO;
    }


    @Override
    public List<TestDO> getTestByIds(List<String> collect) {
        if (CollUtil.isEmpty(collect)) {
            return null;
        }
        QueryWrapper<Test> qw = new QueryWrapper<>();
        qw.in("test_id", collect);
        List<Test> list = super.list(qw);
        List<TestDO> testDOS = list.stream().map(test -> new TestDO(test)).collect(Collectors.toList());
        return testDOS;
    }

    @Override

    public List<TestDO> getTestByWarehouseTest(List<WarehouseTest> collect) {
        List<String> testIds = collect.stream().
                map(warehouseTest -> warehouseTest.getTestId()).collect(Collectors.toList());
        return getTestByIds(testIds);
    }

    @Override
    public void importQuestion(String testID, MultipartFile file) {
        List<List> surface = null;
        try {
            surface = OfficeUtil.excelReaderPage(file.getInputStream(), 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<List> questionData = surface.subList(questionExcelAllocation.getDataLine(), surface.size());
        Iterator<List> iterator = questionData.iterator();
        while (iterator.hasNext()) {
            List item = iterator.next();
            Object o = item.get(questionExcelAllocation.getQuestionColumn());
            if (o==null||o.equals("")) {
                iterator.remove();
            }

        }
        ArrayList<QuestionDO> questionDOs = questionService.tableConversionQuestionDO(questionData);
        List<ExcelException> incorrectDataS = questionService.saveQuestionAll(questionDOs);
        boolean b = exportQuestionDo(testID, questionDOs);
        if (incorrectDataS.size()>0){
            throw new CanUsedException(CanUsedExceptionEnum.TEST_EXCEPTION,incorrectDataS);
        }

    }
}

